package com.mazaiting.face.ui;

import android.Manifest;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.graphics.*;
import android.graphics.drawable.Drawable;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.text.TextUtils;
import android.view.*;
import android.widget.*;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.mazaiting.face.ui.config.FaceConfig;
import com.mazaiting.face.ui.config.FaceStatusEnum;
import com.mazaiting.face.ui.interfaces.ICameraOpenCallback;
import com.mazaiting.face.ui.interfaces.ICompletion;
import com.mazaiting.face.ui.interfaces.IDetectStrategy;
import com.mazaiting.face.ui.utils.CameraUtil;
import com.mazaiting.face.ui.utils.DensityUtil;
import com.mazaiting.face.ui.utils.FileUtil;
import com.mazaiting.face.ui.utils.VolumeUtil;
import com.mazaiting.face.ui.widget.FaceDetectRoundView;
import com.mazaiting.log.L;
import com.mazaiting.permission.PermissionResult;
import com.mazaiting.permission.Permissions;
import com.mazaiting.permission.util.PermissionUtil;
import com.mazaiting.permission.util.State;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 人脸采集页面
 */
@Permissions(value = {
        Manifest.permission.CAMERA,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
}, code = FaceDetectActivity.REQUEST_PERMISSION_CODE)
public class FaceDetectActivity extends AppCompatActivity implements
        SurfaceHolder.Callback,
        Camera.PreviewCallback,
        Camera.ErrorCallback,
        VolumeUtil.VolumeCallback,
        ICompletion,
        View.OnClickListener {
    /**
     * 请求权限码
     */
    public static final int REQUEST_PERMISSION_CODE = 0x100;
    /**
     * 表面视图
     */
    private SurfaceView mSurfaceView;
    /**
     * 表面控制
     */
    private SurfaceHolder mSurfaceHolder;
    /**
     * 声音按钮
     */
    private ImageView mSoundView;
    /**
     * 成功视图
     */
    private ImageView mSuccessView;
    /**
     * 顶部提示
     */
    private TextView mTipsTopView;
    /**
     * 底部提示
     */
    private TextView mTipsBottomView;
    /**
     * 相机
     */
    private Camera mCamera;
    /**
     * 圆形检测视图
     */
    private FaceDetectRoundView mFaceDetectRoundView;
    /**
     * 检测策略
     */
    private IDetectStrategy mDetectStrategy;
    /**
     * 预览尺寸
     */
    private Rect mPreviewRect = new Rect();
    /**
     * 屏幕宽度
     */
    private int mDisplayWidth = 0;
    /**
     * 屏幕高度
     */
    private int mDisplayHeight = 0;
    /**
     * 提示图标
     */
    private Drawable mTipsIcon;
    /**
     * 是否允许声音
     */
    private boolean isEnableSound = true;
    /**
     * 标记是否完成
     */
    private boolean isCompletion = false;
    /**
     * 相机 ID
     */
    private int mCameraId;
    /**
     * 预览宽度
     */
    private int mPreviewWidth;
    /**
     * 预览高度
     */
    private int mPreviewHeight;
    /**
     * 预览角度
     */
    private int mPreviewDegree;
    /**
     * 监听系统音量广播
     */
    private BroadcastReceiver mVolumeReceiver;
    /**
     * 摄像头选择，默认前置摄像头
     */
    private int mCameraIndex = 1;
    /**
     * 线程池
     */
    private ExecutorService mService = Executors.newFixedThreadPool(10);

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 设置屏幕常亮
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_face_detect);

        initConfig();
        initView();
    }

    /**
     * 初始化 View
     */
    private void initView() {
        setSurfaceView();
        // 获取圆形布局
        mFaceDetectRoundView = findViewById(R.id.detect_face_round);
        // 获取声音按钮
        mSoundView = findViewById(R.id.detect_sound);
        // 设置关闭按钮点击监听
        findViewById(R.id.detect_close).setOnClickListener(this);
        // 设置声音按钮点击监听
        findViewById(R.id.detect_switch).setOnClickListener(this);
        // 顶部提示
        mTipsTopView = findViewById(R.id.detect_top_tips);
        // 底部提示
        mTipsBottomView = findViewById(R.id.detect_bottom_tips);
        // 成功视图
        mSuccessView = findViewById(R.id.detect_success_image);
        setSound();
    }

    /**
     * 设置 SurfaceView
     */
    private void setSurfaceView() {
        // 获取帧布局
        FrameLayout frameLayout = findViewById(R.id.detect_surface_layout);
        // 创建 SurfaceView
        mSurfaceView = new SurfaceView(this);
        mSurfaceHolder = mSurfaceView.getHolder();
        // 设置大小
        mSurfaceHolder.setSizeFromLayout();
        // 添加回调
        mSurfaceHolder.addCallback(this);
        // 创建布局参数
        FrameLayout.LayoutParams cameraFL = new FrameLayout.LayoutParams(
                (int) (mDisplayWidth * FaceDetectRoundView.SURFACE_RATIO),
                (int) (mDisplayHeight * FaceDetectRoundView.SURFACE_RATIO),
                Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
        // 设置布局参数
        mSurfaceView.setLayoutParams(cameraFL);
        // 添加 View
        frameLayout.addView(mSurfaceView);
    }

    @Override
    public void onClick(View v) {
        if (R.id.detect_close == v.getId()) {
            // 退出
            onBackPressed();
        } else if (R.id.detect_sound == v.getId()) {
            // 取相反数
            isEnableSound = !isEnableSound;
            setSound();
        } else if (R.id.detect_switch == v.getId()) {
            // 切换前后摄像头
            mCameraIndex = mCameraIndex == 0 ? 1 : 0;
            stopPreview();
            startPreview();
        }
    }

    /**
     * 初始化配置
     */
    private void initConfig() {
        // 人脸配置
        FaceConfig faceConfig = FaceManager.getInstance().getFaceConfig();
        // 设置
        L.setProp(BuildConfig.DEBUG, faceConfig.getTag());
        // 获取屏幕宽高
        Point point = DensityUtil.getMetrics(this);
        // 屏幕宽度
        mDisplayWidth = point.x;
        // 屏幕高度
        mDisplayHeight = point.y;
        // 获取是否开启声音
        isEnableSound = VolumeUtil.isSound(this) && faceConfig.isSound();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        // 权限处理
        PermissionUtil.INSTANCE.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
    }

    /**
     * 权限处理
     *
     * @param state       权限状态
     * @param permissions 权限列表: 注意可为空
     */
    @PermissionResult(REQUEST_PERMISSION_CODE)
    public void permissionResult(State state, List<String> permissions) {
        switch (state) {
            case DENIED:
                PermissionUtil.INSTANCE.requestPermission(this);
            case SUCCESS:
                startPreview();
            case NOT_SHOW:
                L.d("请求不再提示");
        }
        if (null != mDetectStrategy) {
            mDetectStrategy.permissionResult(state, permissions);
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        // 设置音频
        setVolumeControlStream(AudioManager.STREAM_MUSIC);
        // 注册声音广播
        mVolumeReceiver = VolumeUtil.registerVolumeReceiver(this, this);
        // 设置顶部提示信息
        if (mTipsTopView != null) {
            mTipsTopView.setText(R.string.detect_face_in);
        }
        startPreview();
    }

    @Override
    public void onPause() {
        super.onPause();
        // 取消注册声音广播
        VolumeUtil.unRegisterVolumeReceiver(this, mVolumeReceiver);
        mVolumeReceiver = null;
        if (null != mDetectStrategy) {
            mDetectStrategy.unregister();
        }
        stopPreview();
    }

    @Override
    public void volumeChanged() {
        isEnableSound = VolumeUtil.isSound(this);
        setSound();
    }

    @Override
    protected void onDestroy() {
        if (null != mService) {
            mService.shutdown();
        }
        super.onDestroy();
    }

    /**
     * 设置图片
     */
    private void setSound() {
        // 设置图片资源
        mSoundView.setImageResource(isEnableSound ?
                R.mipmap.ic_enable_sound_ext : R.mipmap.ic_disable_sound_ext);
    }

    /**
     * 开始预览
     */
    @SuppressWarnings("SuspiciousNameCombination")
    private void startPreview() {
        // 检测 Surface 视图与 Surface 视图持有人是否为空
        if (null != mSurfaceView && null != mSurfaceView.getHolder()) {
            // 获取 Surface 视图持有者
            mSurfaceHolder = mSurfaceView.getHolder();
            // 添加回调
            mSurfaceHolder.addCallback(this);
        }

        try {
            // 打开摄像头
            mCamera = CameraUtil.open(mCameraIndex, new ICameraOpenCallback() {
                @Override
                public void open(int index) {
                    mCameraId = index;
                }
            });
        } catch (Exception e) {
            L.d(e.getMessage());
        }
        // 判断相机是否开启成功
        if (mCamera == null) {
            // 请求权限
            PermissionUtil.INSTANCE.requestPermission(this);
            return;
        }
        // 获取相机参数
        Camera.Parameters cameraParam = mCamera.getParameters();
        // 设置图片格式
        cameraParam.setPictureFormat(ImageFormat.JPEG);
        // 获取显示角度
        int degree = CameraUtil.displayOrientation(this, mCameraId);
        // 设置预览角度
        mCamera.setDisplayOrientation(degree);
        // 获取预览角度
        mPreviewDegree = CameraUtil.getPreviewDegree(mCameraId, degree);
        // 获取最好的预览尺寸
        Camera.Size previewSize = CameraUtil.getBestPreviewSize(mDisplayWidth, mDisplayHeight, cameraParam);
        // 预览宽度
        mPreviewWidth = previewSize.width;
        // 预览高度
        mPreviewHeight = previewSize.height;
        // 预览矩形
        mPreviewRect.set(0, 0, mPreviewHeight, mPreviewWidth);
        // 设置预览尺寸
        cameraParam.setPreviewSize(mPreviewWidth, mPreviewHeight);
        // 设置曝光值
        cameraParam.setExposureCompensation(5);
        // 设置相机参数
        if (null != mDetectStrategy) {
            cameraParam = mDetectStrategy.setParameters(cameraParam);
        }

        // 设置相机参数
        mCamera.setParameters(cameraParam);

        try {
            // 设置预览
            mCamera.setPreviewDisplay(mSurfaceHolder);
            // 停止预览
            mCamera.stopPreview();
            // 设置错误回调
            mCamera.setErrorCallback(this);
            // 设置预览回调
            mCamera.setPreviewCallback(this);
            // 开始预览
            mCamera.startPreview();
        } catch (Exception e) {
            e.printStackTrace();
            // 释放相机
            CameraUtil.releaseCamera(mCamera);
            mCamera = null;
        }
    }

    /**
     * 停止预览
     */
    private void stopPreview() {
        // 检测相机是否为空
        if (null != mCamera) {
            try {
                // 移除异常回调
                mCamera.setErrorCallback(null);
                // 移除预览回调
                mCamera.setPreviewCallback(null);
                // 停止预览
                mCamera.stopPreview();
            } catch (Exception e) {
                L.d(e.getMessage());
            } finally {
                CameraUtil.releaseCamera(mCamera);
                mCamera = null;
            }
        }
        // 移除回调
        if (null != mSurfaceHolder) {
            mSurfaceHolder.removeCallback(this);
        }
        if (null != mDetectStrategy) {
            mDetectStrategy = null;
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if (null == holder.getSurface()) return;
        startPreview();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }

    @Override
    public void onPreviewFrame(final byte[] data, final Camera camera) {
        // 检测是否完成
        if (isCompletion) {
            return;
        }
        // 设置检测策略
        if (null == mDetectStrategy && null != mFaceDetectRoundView && mFaceDetectRoundView.getRound() > 0) {
            // 获取检测策略模块
            mDetectStrategy = FaceManager.getInstance().getDetectStrategyModule();
            // 挂载当前 Activity
            mDetectStrategy.register(this);
        }

        mService.execute(new Runnable() {
            @Override
            public void run() {
                // 获取 YUV 尺寸
                byte[] rawImage = FileUtil.getYuvImageData(data, mPreviewWidth, mPreviewHeight);
                // 获取预览图像
                Bitmap bitmap = FileUtil.byteToBitmap(rawImage);
                // 获取检测矩形
                Rect detectRect = FaceDetectRoundView.getPreviewDetectRect(mDisplayWidth, mPreviewHeight, mPreviewWidth);
                // 获取旋转之后的图像
                Bitmap rotatedBitmap = FileUtil.rotatedImageView(bitmap, -mPreviewDegree);
                // 获取指定区域
                Bitmap specificBitmap = FileUtil.getSpecificArea(rotatedBitmap, detectRect);
                // 获取二进制数据
                byte[] bytes = FileUtil.bitmapToByte(specificBitmap);
                // 保存
                // FileUtil.saveBitmapFile(specificBitmap);
                if (mDetectStrategy != null) {
                    // 检测
                    mDetectStrategy.detect(bytes);
                }
            }
        });
    }

    @Override
    public void onError(int error, Camera camera) {
    }

    @Override
    public void onDetectCompletion(final FaceStatusEnum status, final String message, final byte[] data) {
        if (isCompletion) {
            return;
        }
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // 刷新视图
                onRefreshView(status, message);
                // 如果检测成功, 保存图片
                if (status == FaceStatusEnum.OK) {
                    isCompletion = true;
                    // 保存图片
                    FileUtil.byteToImageFile(data);
                    soundAndVibrator();
                    // 检测成功
                    setResult(Activity.RESULT_OK);
                    finish();
                }
            }
        });
    }

    /**
     * 播放声音和震动
     */
    private void soundAndVibrator() {
        VolumeUtil.playSound(this, R.raw.face_good);
        vibrator();
    }

    /**
     * 震动
     */
    private void vibrator() {
        Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
        vibrator.vibrate(new long[]{100L, 200L, 100L, 200L}, 1);
    }

    /**
     * 刷新视图
     *
     * @param status  检测状态
     * @param message 消息
     */
    private void onRefreshView(FaceStatusEnum status, String message) {
        switch (status) {
            case OK:
                // 刷新提示信息
                onRefreshTipsView(false, message);
                // 设置底部提示信息
                mTipsBottomView.setText("");
                // 设置状态
                mFaceDetectRoundView.processDrawState(false);
                // 刷新成功视图
                onRefreshSuccessView(true);
                break;
            case OUT_OF_UP_MAX_RANGE:
            case OUT_OF_DOWN_MAX_RANGE:
            case OUT_OF_LEFT_MAX_RANGE:
            case OUT_OF_RIGHT_MAX_RANGE:
                onRefreshTipsView(true, message);
                mTipsBottomView.setText(message);
                mFaceDetectRoundView.processDrawState(true);
                onRefreshSuccessView(false);
                break;
            default:
                onRefreshTipsView(false, message);
                mTipsBottomView.setText("");
                mFaceDetectRoundView.processDrawState(true);
                onRefreshSuccessView(false);
        }
    }

    /**
     * 刷新提示视图
     *
     * @param isAlert 是否提示
     * @param message 信息
     */
    private void onRefreshTipsView(boolean isAlert, String message) {
        // 判断是否提示
        if (isAlert) {
            // 获取图标
            if (mTipsIcon == null) {
                // 获取图标
                mTipsIcon = getResources().getDrawable(R.mipmap.ic_warning);
                // 设置图标大小
                mTipsIcon.setBounds(0, 0, (int) (mTipsIcon.getMinimumWidth() * 0.7f),
                        (int) (mTipsIcon.getMinimumHeight() * 0.7f));
                // 设置内边距
                mTipsTopView.setCompoundDrawablePadding(15);
            }
            // 设置背景
            mTipsTopView.setBackgroundResource(R.drawable.bg_tips);
            // 设置文本
            mTipsTopView.setText(R.string.detect_standard);
            // 设置内容图
            mTipsTopView.setCompoundDrawables(mTipsIcon, null, null, null);
        } else {
            // 设置资源
            mTipsTopView.setBackgroundResource(R.drawable.bg_tips_no);
            // 清空内容图
            mTipsTopView.setCompoundDrawables(null, null, null, null);
            // 设置内容
            if (!TextUtils.isEmpty(message)) {
                mTipsTopView.setText(message);
            }
        }
    }

    /**
     * 刷新成功视图
     *
     * @param isShow 是否系那是
     */
    private void onRefreshSuccessView(boolean isShow) {
        mSuccessView.setVisibility(isShow ? View.VISIBLE : View.INVISIBLE);
    }
}
